package cn.cimoc.config.aop;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;


/**
 * @author LGZ
 * @date 2021/5/9 22:17
 * <p>
 *   通过AOP记录每一个请求访问接口的相关信息并输出到日志文件
 * </p>
 */
@Aspect
@Slf4j
@Component
public class ControllerAspect {
    private static final int MAX_TIME = 5000; // 超过这个时间，接口访问过慢

    public Object runAndSaveLog(ProceedingJoinPoint pjp) throws Throwable {
        long beginTime = System.currentTimeMillis();
        // 获取当前对象
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (attributes == null) {
            return pjp.proceed();
        }
        HttpServletRequest req = attributes.getRequest();


        Object result = null;
        // 获取目标对象
        Object target = pjp.getTarget();
        // 获取方法签名对象
        Signature signature = pjp.getSignature();
        // 默认是16的容量，当容量不够时，新建一个容量为2 * capacity + 2的数组进行复制
        // 直接给一个初始容量可以提高效率
        StringBuilder logInfo = new StringBuilder(150);
        logInfo.append("AOP-Log: ")
                // uri
                .append("uri=[")
                .append(req.getRequestURI())
                .append("]; ")
                // ip
                .append("client=[")
                .append(req.getRemoteHost())
                .append("]; ")
                // GET\POST\PUT\...
                .append("httpMethod=[")
                .append(req.getMethod())
                .append("]; ")
                // controller
                .append("Controller=[")
                .append(target.getClass().getSimpleName())
                .append("]; ")
                // method
                .append("method=[")
                .append(signature.getName())
                .append("]; ");



        try {
            result = pjp.proceed();
        } catch (Throwable e) {
            // ------------------------------------ //
            if (!"成功".equals(e.getMessage())) {
                // 错误信息
                logInfo.append("error=[")
                        .append(e.getMessage())
                        .append("]; ")
                        .append("status=[FAIL]");
                log.error(logInfo.toString());
            } else {
                long endTime = System.currentTimeMillis();
                // 接口访问时间
                logInfo.append("time=[")
                        .append(endTime - beginTime)
                        .append("ms]; ")
                        .append("status=[OK]");
                log.info(logInfo.toString());
            }
            // ------------------------------------ //
            throw e;
        }

        // ------------------------------------ //

        long endTime = System.currentTimeMillis();
        logInfo.append("time=[")
                .append(endTime - beginTime)
                .append("ms]; ")
                .append("status=[OK]");
        log.info(logInfo.toString());

        // ------------------------------------ //
        return result;

    }

    @Around("@within(org.springframework.stereotype.Controller)")
    Object aroundController(ProceedingJoinPoint pjp) throws Throwable {
        return runAndSaveLog(pjp);
    }

    @Around("@within(org.springframework.web.bind.annotation.RestController)")
    Object aroundRestController(ProceedingJoinPoint pjp) throws Throwable {
        return runAndSaveLog(pjp);
    }

}
